{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1. 加载依赖库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    }
   ],
   "source": [
    "import keras.backend as K\n",
    "from keras.models import Model\n",
    "from keras.layers import Input, Reshape, Permute, Dense, Activation, Flatten, Conv2D\n",
    "from keras.layers import MaxPooling2D, AveragePooling2D, GlobalAveragePooling2D, GlobalMaxPool2D, BatchNormalization\n",
    "from keras.layers import Convolution2D, UpSampling2D, AtrousConvolution2D, ZeroPadding2D, Lambda, Conv2DTranspose\n",
    "from keras.layers import multiply, add, concatenate, Concatenate\n",
    "from keras.layers import LocallyConnected2D\n",
    "from keras.layers import add\n",
    "from keras.preprocessing.image import ImageDataGenerator\n",
    "from keras.models import load_model\n",
    "from keras.optimizers import SGD\n",
    "from keras.callbacks import ModelCheckpoint, EarlyStopping\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "from keras.utils import np_utils\n",
    "import cv2\n",
    "import random\n",
    "from keras.layers.advanced_activations import PReLU, LeakyReLU\n",
    "import tifffile\n",
    "from keras.backend import tf as ktf\n",
    "from glob import glob\n",
    "from random import choice"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"0\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2. 全局变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "NB_CLASS = 5\n",
    "IMG_WIDTH = 512\n",
    "IMG_HEIGHT = 512\n",
    "\n",
    "# 数据路径\n",
    "img_type = '.tif'\n",
    "TRAIN_TOP_PATH = 'E:/Semantic-Segmentation/four_dataset/VAIHINGEN/train_crop_top/'\n",
    "\n",
    "VAL_TOP_PATH = 'E:/Semantic-Segmentation/four_dataset/VAIHINGEN/test_crop_top/'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3. 模型定义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import keras.backend as K\n",
    "from keras.models import Model\n",
    "from keras.layers import Input, Conv1D, Conv2D, BatchNormalization, Activation\n",
    "from keras.layers import UpSampling2D, add, concatenate, Dropout\n",
    "from keras_superpixel_pooling_new import *\n",
    "from keras_superpixel_unpooling import *\n",
    "\n",
    "\n",
    "def conv3x3(x, out_filters, strides=(1, 1)):\n",
    "    x = Conv2D(out_filters, 3, padding='same', strides=strides, use_bias=False, kernel_initializer='he_normal')(x)\n",
    "    return x\n",
    "\n",
    "\n",
    "def basic_Block(input, out_filters, strides=(1, 1), with_conv_shortcut=False):\n",
    "    x = conv3x3(input, out_filters, strides)\n",
    "    x = BatchNormalization(axis=3)(x)\n",
    "    x = Activation('relu')(x)\n",
    "\n",
    "    x = conv3x3(x, out_filters)\n",
    "    x = BatchNormalization(axis=3)(x)\n",
    "\n",
    "    if with_conv_shortcut:\n",
    "        residual = Conv2D(out_filters, 1, strides=strides, use_bias=False, kernel_initializer='he_normal')(input)\n",
    "        residual = BatchNormalization(axis=3)(residual)\n",
    "        x = add([x, residual])\n",
    "    else:\n",
    "        x = add([x, input])\n",
    "\n",
    "    x = Activation('relu')(x)\n",
    "    return x\n",
    "\n",
    "\n",
    "def bottleneck_Block(input, out_filters, strides=(1, 1), with_conv_shortcut=False):\n",
    "    expansion = 4\n",
    "    de_filters = int(out_filters / expansion)\n",
    "\n",
    "    x = Conv2D(de_filters, 1, use_bias=False, kernel_initializer='he_normal')(input)\n",
    "    x = BatchNormalization(axis=3)(x)\n",
    "    x = Activation('relu')(x)\n",
    "\n",
    "    x = Conv2D(de_filters, 3, strides=strides, padding='same', use_bias=False, kernel_initializer='he_normal')(x)\n",
    "    x = BatchNormalization(axis=3)(x)\n",
    "    x = Activation('relu')(x)\n",
    "\n",
    "    x = Conv2D(out_filters, 1, use_bias=False, kernel_initializer='he_normal')(x)\n",
    "    x = BatchNormalization(axis=3)(x)\n",
    "\n",
    "    if with_conv_shortcut:\n",
    "        residual = Conv2D(out_filters, 1, strides=strides, use_bias=False, kernel_initializer='he_normal')(input)\n",
    "        residual = BatchNormalization(axis=3)(residual)\n",
    "        x = add([x, residual])\n",
    "    else:\n",
    "        x = add([x, input])\n",
    "\n",
    "    x = Activation('relu')(x)\n",
    "    return x\n",
    "\n",
    "\n",
    "def stem_net(input):\n",
    "    x = Conv2D(64, 3, strides=(2, 2), padding='same', use_bias=False, kernel_initializer='he_normal')(input)\n",
    "    x = BatchNormalization(axis=3)(x)\n",
    "    x = Activation('relu')(x)\n",
    "\n",
    "    # x = Conv2D(64, 3, strides=(2, 2), padding='same', use_bias=False, kernel_initializer='he_normal')(x)\n",
    "    # x = BatchNormalization(axis=3)(x)\n",
    "    # x = Activation('relu')(x)\n",
    "\n",
    "    x = bottleneck_Block(x, 256, with_conv_shortcut=True)\n",
    "    x = bottleneck_Block(x, 256, with_conv_shortcut=False)\n",
    "    x = bottleneck_Block(x, 256, with_conv_shortcut=False)\n",
    "    x = bottleneck_Block(x, 256, with_conv_shortcut=False)\n",
    "\n",
    "    return x\n",
    "\n",
    "\n",
    "def transition_layer1(x, out_filters_list=[32, 64]):\n",
    "    x0 = Conv2D(out_filters_list[0], 3, padding='same', use_bias=False, kernel_initializer='he_normal')(x)\n",
    "    x0 = BatchNormalization(axis=3)(x0)\n",
    "    x0 = Activation('relu')(x0)\n",
    "\n",
    "    x1 = Conv2D(out_filters_list[1], 3, strides=(2, 2),\n",
    "                padding='same', use_bias=False, kernel_initializer='he_normal')(x)\n",
    "    x1 = BatchNormalization(axis=3)(x1)\n",
    "    x1 = Activation('relu')(x1)\n",
    "\n",
    "    return [x0, x1]\n",
    "\n",
    "\n",
    "def make_branch1_0(x, out_filters=32):\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    return x\n",
    "\n",
    "\n",
    "def make_branch1_1(x, out_filters=64):\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    return x\n",
    "\n",
    "\n",
    "def fuse_layer1(x):\n",
    "    x0_0 = x[0]\n",
    "    x0_1 = Conv2D(32, 1, use_bias=False, kernel_initializer='he_normal')(x[1])\n",
    "    x0_1 = BatchNormalization(axis=3)(x0_1)\n",
    "    x0_1 = UpSampling2D(size=(2, 2))(x0_1)\n",
    "    x0 = add([x0_0, x0_1])\n",
    "\n",
    "    x1_0 = Conv2D(64, 3, strides=(2, 2), padding='same', use_bias=False, kernel_initializer='he_normal')(x[0])\n",
    "    x1_0 = BatchNormalization(axis=3)(x1_0)\n",
    "    x1_1 = x[1]\n",
    "    x1 = add([x1_0, x1_1])\n",
    "    return [x0, x1]\n",
    "\n",
    "\n",
    "def transition_layer2(x, out_filters_list=[32, 64, 128]):\n",
    "    x0 = Conv2D(out_filters_list[0], 3, padding='same', use_bias=False, kernel_initializer='he_normal')(x[0])\n",
    "    x0 = BatchNormalization(axis=3)(x0)\n",
    "    x0 = Activation('relu')(x0)\n",
    "\n",
    "    x1 = Conv2D(out_filters_list[1], 3, padding='same', use_bias=False, kernel_initializer='he_normal')(x[1])\n",
    "    x1 = BatchNormalization(axis=3)(x1)\n",
    "    x1 = Activation('relu')(x1)\n",
    "\n",
    "    x2 = Conv2D(out_filters_list[2], 3, strides=(2, 2),\n",
    "                padding='same', use_bias=False, kernel_initializer='he_normal')(x[1])\n",
    "    x2 = BatchNormalization(axis=3)(x2)\n",
    "    x2 = Activation('relu')(x2)\n",
    "\n",
    "    return [x0, x1, x2]\n",
    "\n",
    "\n",
    "def make_branch2_0(x, out_filters=32):\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    return x\n",
    "\n",
    "\n",
    "def make_branch2_1(x, out_filters=64):\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    return x\n",
    "\n",
    "\n",
    "def make_branch2_2(x, out_filters=128):\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    return x\n",
    "\n",
    "\n",
    "def fuse_layer2(x):\n",
    "    x0_0 = x[0]\n",
    "    x0_1 = Conv2D(32, 1, use_bias=False, kernel_initializer='he_normal')(x[1])\n",
    "    x0_1 = BatchNormalization(axis=3)(x0_1)\n",
    "    x0_1 = UpSampling2D(size=(2, 2))(x0_1)\n",
    "    x0_2 = Conv2D(32, 1, use_bias=False, kernel_initializer='he_normal')(x[2])\n",
    "    x0_2 = BatchNormalization(axis=3)(x0_2)\n",
    "    x0_2 = UpSampling2D(size=(4, 4))(x0_2)\n",
    "    x0 = add([x0_0, x0_1, x0_2])\n",
    "\n",
    "    x1_0 = Conv2D(64, 3, strides=(2, 2), padding='same', use_bias=False, kernel_initializer='he_normal')(x[0])\n",
    "    x1_0 = BatchNormalization(axis=3)(x1_0)\n",
    "    x1_1 = x[1]\n",
    "    x1_2 = Conv2D(64, 1, use_bias=False, kernel_initializer='he_normal')(x[2])\n",
    "    x1_2 = BatchNormalization(axis=3)(x1_2)\n",
    "    x1_2 = UpSampling2D(size=(2, 2))(x1_2)\n",
    "    x1 = add([x1_0, x1_1, x1_2])\n",
    "\n",
    "    x2_0 = Conv2D(32, 3, strides=(2, 2), padding='same', use_bias=False, kernel_initializer='he_normal')(x[0])\n",
    "    x2_0 = BatchNormalization(axis=3)(x2_0)\n",
    "    x2_0 = Activation('relu')(x2_0)\n",
    "    x2_0 = Conv2D(128, 3, strides=(2, 2), padding='same', use_bias=False, kernel_initializer='he_normal')(x2_0)\n",
    "    x2_0 = BatchNormalization(axis=3)(x2_0)\n",
    "    x2_1 = Conv2D(128, 3, strides=(2, 2), padding='same', use_bias=False, kernel_initializer='he_normal')(x[1])\n",
    "    x2_1 = BatchNormalization(axis=3)(x2_1)\n",
    "    x2_2 = x[2]\n",
    "    x2 = add([x2_0, x2_1, x2_2])\n",
    "    return [x0, x1, x2]\n",
    "\n",
    "\n",
    "def transition_layer3(x, out_filters_list=[32, 64, 128, 256]):\n",
    "    x0 = Conv2D(out_filters_list[0], 3, padding='same', use_bias=False, kernel_initializer='he_normal')(x[0])\n",
    "    x0 = BatchNormalization(axis=3)(x0)\n",
    "    x0 = Activation('relu')(x0)\n",
    "\n",
    "    x1 = Conv2D(out_filters_list[1], 3, padding='same', use_bias=False, kernel_initializer='he_normal')(x[1])\n",
    "    x1 = BatchNormalization(axis=3)(x1)\n",
    "    x1 = Activation('relu')(x1)\n",
    "\n",
    "    x2 = Conv2D(out_filters_list[2], 3, padding='same', use_bias=False, kernel_initializer='he_normal')(x[2])\n",
    "    x2 = BatchNormalization(axis=3)(x2)\n",
    "    x2 = Activation('relu')(x2)\n",
    "\n",
    "    x3 = Conv2D(out_filters_list[3], 3, strides=(2, 2),\n",
    "                padding='same', use_bias=False, kernel_initializer='he_normal')(x[2])\n",
    "    x3 = BatchNormalization(axis=3)(x3)\n",
    "    x3 = Activation('relu')(x3)\n",
    "\n",
    "    return [x0, x1, x2, x3]\n",
    "\n",
    "\n",
    "def make_branch3_0(x, out_filters=32):\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    return x\n",
    "\n",
    "\n",
    "def make_branch3_1(x, out_filters=64):\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    return x\n",
    "\n",
    "\n",
    "def make_branch3_2(x, out_filters=128):\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    return x\n",
    "\n",
    "\n",
    "def make_branch3_3(x, out_filters=256):\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    x = basic_Block(x, out_filters, with_conv_shortcut=False)\n",
    "    return x\n",
    "\n",
    "\n",
    "def fuse_layer3(x):\n",
    "    x0_0 = x[0]\n",
    "    x0_1 = Conv2D(32, 1, use_bias=False, kernel_initializer='he_normal')(x[1])\n",
    "    x0_1 = BatchNormalization(axis=3)(x0_1)\n",
    "    x0_1 = UpSampling2D(size=(2, 2))(x0_1)\n",
    "    x0_2 = Conv2D(32, 1, use_bias=False, kernel_initializer='he_normal')(x[2])\n",
    "    x0_2 = BatchNormalization(axis=3)(x0_2)\n",
    "    x0_2 = UpSampling2D(size=(4, 4))(x0_2)\n",
    "    x0_3 = Conv2D(32, 1, use_bias=False, kernel_initializer='he_normal')(x[3])\n",
    "    x0_3 = BatchNormalization(axis=3)(x0_3)\n",
    "    x0_3 = UpSampling2D(size=(8, 8))(x0_3)\n",
    "    x0 = concatenate([x0_0, x0_1, x0_2, x0_3], axis=-1)\n",
    "    return x0\n",
    "\n",
    "\n",
    "def final_layer(x, classes=1):\n",
    "    x = Activation('relu')(x)\n",
    "    x = Conv2D(classes, 1, use_bias=False, kernel_initializer='he_normal')(x)\n",
    "    x = BatchNormalization(axis=3)(x)\n",
    "    x = Activation('softmax', name='Classification')(x)\n",
    "    return x\n",
    "\n",
    "\n",
    "def seg_hrnet(batch = 1, height=256, width=256, channel=3, classes=6):\n",
    "    inputs = Input(batch_shape=(batch,) + (height, width, channel))\n",
    "    slic_feature_map = Input(batch_shape=(batch,) + (height, width))\n",
    "\n",
    "    x0 = stem_net(inputs)\n",
    "\n",
    "    x1 = transition_layer1(x0)\n",
    "    x1_0 = make_branch1_0(x1[0])\n",
    "    x1_1 = make_branch1_1(x1[1])\n",
    "    x1 = fuse_layer1([x1_0, x1_1])\n",
    "\n",
    "    x2 = transition_layer2(x1)\n",
    "    x2_0 = make_branch2_0(x2[0])\n",
    "    x2_1 = make_branch2_1(x2[1])\n",
    "    x2_2 = make_branch2_2(x2[2])\n",
    "    x2 = fuse_layer2([x2_0, x2_1, x2_2])\n",
    "\n",
    "    x3 = transition_layer3(x2)\n",
    "    x3_0 = make_branch3_0(x3[0])\n",
    "    x3_1 = make_branch3_1(x3[1])\n",
    "    x3_2 = make_branch3_2(x3[2])\n",
    "    x3_3 = make_branch3_3(x3[3])\n",
    "    x3 = fuse_layer3([x3_0, x3_1, x3_2, x3_3])\n",
    "    x3 = UpSampling2D(size=(2, 2))(x3)\n",
    "\n",
    "    # ORIGINAL\n",
    "    x4_1 = Conv2D(32, 1, use_bias=False, kernel_initializer='he_normal')(x3)\n",
    "    x4_1 = BatchNormalization(axis=-1)(x4_1)\n",
    "\n",
    "    # SUPERPIXEL\n",
    "    x4_2 = SuperpixelPooling(num_superpixels=100)([x3, slic_feature_map])\n",
    "    x4_2 = Conv1D(32, 1, use_bias=False, kernel_initializer='he_normal')(x4_2)\n",
    "    x4_2 = BatchNormalization(axis=-1)(x4_2)\n",
    "    x4_2 = SuperpixelUnpooling(num_superpixels=100, num_channels=32, batch_size=1,\n",
    "                               superpixel_map_shapes=(height, width))([x4_2, slic_feature_map])\n",
    "\n",
    "    x4 = add([x4_1, x4_2])\n",
    "\n",
    "    out = final_layer(x4, classes=classes)\n",
    "\n",
    "    model = Model(inputs=[inputs, slic_feature_map], outputs=out)\n",
    "\n",
    "    return model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4. 数据加载generator"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.1 读取一个batch的图片"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "from skimage.segmentation import slic\n",
    "# 读取图片函数\n",
    "def read_img(top_paths):\n",
    "    top_imgs = []\n",
    "    label_imgs = []\n",
    "    slic_segs = []\n",
    "    for top_path in top_paths:\n",
    "        label_path = top_path.replace('top', 'label')\n",
    "        \n",
    "        top_img = tifffile.imread(top_path)\n",
    "        label_img = tifffile.imread(label_path)\n",
    "        slic_seg = slic(img, n_segments=100, compactness=30, max_iter=10, convert2lab=False, enforce_connectivity=False)\n",
    "        \n",
    "        \n",
    "        top_img = top_img / 255.0\n",
    "        \n",
    "        label_img = np.expand_dims(label_img, axis=2)\n",
    "        label_img = np_utils.to_categorical(label_img, num_classes=6)\n",
    "        label_img = label_img[:, :, 0:5]\n",
    "\n",
    "        top_imgs.append(top_img)\n",
    "        label_imgs.append(label_img)\n",
    "        slic_segs.append(slic_seg)\n",
    "\n",
    "    return np.array(top_imgs), np.array(label_imgs), np.array(slic_segs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.2 获取批次函数，其实就是一个generator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def batch_generator(top_path, batch_size):\n",
    "    while 1:\n",
    "        for i in range(0, len(top_path), batch_size):\n",
    "            top, label, slic_seg = read_img(top_path[i:i + batch_size])\n",
    "\n",
    "            yield ({'input_1': top, 'input_2': slic_seg}, {'Classification': label})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.3 读取数据路径"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_data_paths(train_crop_top_dir, test_crop_top_dir):\n",
    "    train_crop_top_paths = glob(os.path.join(train_crop_top_dir, '*.tif'))\n",
    "    test_crop_top_paths = glob(os.path.join(test_crop_top_dir, '*.tif'))\n",
    "\n",
    "    # 随机打乱训练数据\n",
    "    index = [m for m in range(len(train_crop_top_paths))]\n",
    "    random.shuffle(index)\n",
    "    train_crop_top_paths = np.array(train_crop_top_paths)[index]\n",
    "\n",
    "    print(index)\n",
    "    return train_crop_top_paths, test_crop_top_paths"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. 定义评价指标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def f1(y_true, y_pred):\n",
    "    def recall(y_true, y_pred):\n",
    "        \"\"\"Recall metric.\n",
    "\n",
    "        Only computes a batch-wise average of recall.\n",
    "\n",
    "        Computes the recall, a metric for multi-label classification of\n",
    "        how many relevant items are selected.\n",
    "        \"\"\"\n",
    "        true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))\n",
    "        possible_positives = K.sum(K.round(K.clip(y_true, 0, 1)))\n",
    "        recall = true_positives / (possible_positives + K.epsilon())\n",
    "        return recall\n",
    "\n",
    "    def precision(y_true, y_pred):\n",
    "        \"\"\"Precision metric.\n",
    "\n",
    "        Only computes a batch-wise average of precision.\n",
    "\n",
    "        Computes the precision, a metric for multi-label classification of\n",
    "        how many selected items are relevant.\n",
    "        \"\"\"\n",
    "        true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))\n",
    "        predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1)))\n",
    "        precision = true_positives / (predicted_positives + K.epsilon())\n",
    "        return precision\n",
    "    precision = precision(y_true, y_pred)\n",
    "    recall = recall(y_true, y_pred)\n",
    "    return 2*((precision*recall)/(precision+recall+K.epsilon()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. 主函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "Operands could not be broadcast together with shapes (256, 2, 32) (256, 4, 32)",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-9-861cda207b8a>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0m__name__\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;34m'__main__'\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m     \u001b[1;31m# Create a Keras Model\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m     \u001b[0mmodel\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mseg_hrnet\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mIMG_WIDTH\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mIMG_HEIGHT\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m3\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mNB_CLASS\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      4\u001b[0m     \u001b[0mmodel\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msummary\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m<ipython-input-4-1c862e146e09>\u001b[0m in \u001b[0;36mseg_hrnet\u001b[1;34m(batch, height, width, channel, classes)\u001b[0m\n\u001b[0;32m    279\u001b[0m     \u001b[0mx2_1\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmake_branch2_1\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx2\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    280\u001b[0m     \u001b[0mx2_2\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmake_branch2_2\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx2\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 281\u001b[1;33m     \u001b[0mx2\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mfuse_layer2\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mx2_0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mx2_1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mx2_2\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    282\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    283\u001b[0m     \u001b[0mx3\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtransition_layer3\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m<ipython-input-4-1c862e146e09>\u001b[0m in \u001b[0;36mfuse_layer2\u001b[1;34m(x)\u001b[0m\n\u001b[0;32m    166\u001b[0m     \u001b[0mx0_2\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mBatchNormalization\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maxis\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m3\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx0_2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    167\u001b[0m     \u001b[0mx0_2\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mUpSampling2D\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msize\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m4\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m4\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx0_2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 168\u001b[1;33m     \u001b[0mx0\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0madd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mx0_0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mx0_1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mx0_2\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    169\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    170\u001b[0m     \u001b[0mx1_0\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mConv2D\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m64\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m3\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mstrides\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mpadding\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m'same'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0muse_bias\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mFalse\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkernel_initializer\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m'he_normal'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\Anaconda3\\lib\\site-packages\\keras\\layers\\merge.py\u001b[0m in \u001b[0;36madd\u001b[1;34m(inputs, **kwargs)\u001b[0m\n\u001b[0;32m    553\u001b[0m     \u001b[0;31m`\u001b[0m\u001b[0;31m`\u001b[0m\u001b[0;31m`\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    554\u001b[0m     \"\"\"\n\u001b[1;32m--> 555\u001b[1;33m     \u001b[1;32mreturn\u001b[0m \u001b[0mAdd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minputs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    556\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    557\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\Anaconda3\\lib\\site-packages\\keras\\engine\\base_layer.py\u001b[0m in \u001b[0;36m__call__\u001b[1;34m(self, inputs, **kwargs)\u001b[0m\n\u001b[0;32m    429\u001b[0m                                          \u001b[1;34m'You can build it manually via: '\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    430\u001b[0m                                          '`layer.build(batch_input_shape)`')\n\u001b[1;32m--> 431\u001b[1;33m                 \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbuild\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0munpack_singleton\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minput_shapes\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    432\u001b[0m                 \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbuilt\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mTrue\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    433\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\Anaconda3\\lib\\site-packages\\keras\\layers\\merge.py\u001b[0m in \u001b[0;36mbuild\u001b[1;34m(self, input_shape)\u001b[0m\n\u001b[0;32m     89\u001b[0m                 \u001b[0mshape\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0minput_shape\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     90\u001b[0m             output_shape = self._compute_elemwise_op_output_shape(output_shape,\n\u001b[1;32m---> 91\u001b[1;33m                                                                   shape)\n\u001b[0m\u001b[0;32m     92\u001b[0m         \u001b[1;31m# If the inputs have different ranks, we have to reshape them\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     93\u001b[0m         \u001b[1;31m# to make them broadcastable.\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\Anaconda3\\lib\\site-packages\\keras\\layers\\merge.py\u001b[0m in \u001b[0;36m_compute_elemwise_op_output_shape\u001b[1;34m(self, shape1, shape2)\u001b[0m\n\u001b[0;32m     59\u001b[0m                     raise ValueError('Operands could not be broadcast '\n\u001b[0;32m     60\u001b[0m                                      \u001b[1;34m'together with shapes '\u001b[0m \u001b[1;33m+\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 61\u001b[1;33m                                      str(shape1) + ' ' + str(shape2))\n\u001b[0m\u001b[0;32m     62\u001b[0m                 \u001b[0moutput_shape\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     63\u001b[0m         \u001b[1;32mreturn\u001b[0m \u001b[0mtuple\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0moutput_shape\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mValueError\u001b[0m: Operands could not be broadcast together with shapes (256, 2, 32) (256, 4, 32)"
     ]
    }
   ],
   "source": [
    "if __name__ == '__main__':\n",
    "    # Create a Keras Model\n",
    "    model = seg_hrnet(IMG_WIDTH, IMG_HEIGHT, 3, NB_CLASS)\n",
    "    model.summary()\n",
    "\n",
    "    # 优化器函数\n",
    "    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=[f1, 'acc'])\n",
    "\n",
    "    # 获取路径列表\n",
    "    train_crop_top_paths, test_crop_top_paths = get_data_paths(TRAIN_TOP_PATH, VAL_TOP_PATH)\n",
    "\n",
    "    model_checkpoint = ModelCheckpoint('hrnet_superpixel.hdf5', monitor='val_f1', mode='max', verbose=1, save_best_only=True)\n",
    "    early_stop = EarlyStopping(monitor='val_f1', mode='max', patience=20)\n",
    "    check_point_list = [model_checkpoint, early_stop]\n",
    "\n",
    "    result = model.fit_generator(\n",
    "        generator=batch_generator(train_crop_top_paths, 1),\n",
    "        steps_per_epoch=10196,\n",
    "        epochs=500,\n",
    "        verbose=1,\n",
    "        validation_data=batch_generator(test_crop_top_paths, 1),\n",
    "        validation_steps=398,\n",
    "        callbacks=check_point_list,\n",
    "        class_weight=[0.7880542, 0.84201391, 1.05645948, 0.94926901, 18.17903545])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure()\n",
    "plt.plot(result.epoch, result.history['f1'], label=\"acc\")\n",
    "plt.plot(result.epoch, result.history['val_f1'], label=\"val_acc\")\n",
    "plt.scatter(result.epoch, result.history['f1'], marker='*')\n",
    "plt.scatter(result.epoch, result.history['val_f1'])\n",
    "plt.legend(loc='under right')\n",
    "plt.show()\n",
    "\n",
    "plt.figure()\n",
    "plt.plot(result.epoch, result.history['loss'], label=\"loss\")\n",
    "plt.plot(result.epoch, result.history['val_loss'], label=\"val_loss\")\n",
    "plt.scatter(result.epoch, result.history['loss'], marker='*')\n",
    "plt.scatter(result.epoch, result.history['val_loss'], marker='*')\n",
    "plt.legend(loc='upper right')\n",
    "plt.show()\n",
    "\n",
    "with open('unet_resnet_101.txt', 'w') as f:\n",
    "    f.write(str(result.history))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
